#include <tinx/task.h>
#include <tinx/fs.h>
#include <tinx/string.h>
#include <tinx/assert.h>

int match_name(char *name, char *entry_name, char **next)
{
    char *lhs = (char *)name;
    char *rhs = (char *)entry_name;
    // 循环比较
    while (*lhs == *rhs && *lhs != EOS && *rhs != EOS)
    {
        lhs++;
        rhs++;
    }
    if (*rhs)
        return false;
    // 下一个不是分割符返回 false
    if (*lhs && !IS_SEPARATOR(*lhs))
        return false;
    // 是分隔符就获得下一个节点的名字, 并且返回 true
    if (IS_SEPARATOR(*lhs))
        lhs++;
    *next = lhs;
    return true;
}

inode_t *namedd(char *pathname, char **next, inode_t *dir)
{
    dir->count++;
    char *name = pathname;
    *next = name;
    if (!*name)
        return dir;
    char *lastname = strrname(name);
    assert(!lastname || lastname >= name);
    if (!lastname || lastname == name)
        return dir;

    inode_t *inode = NULL;
    while (true)
    {
        if (match_name(name, "..", next) && dir == dir->super->iroot)
        {
            super_t *super = dir->super;
            inode = super->imount;
            inode->count++;
            iput(dir);
            dir = inode;
        }
        if (dir->op->namei(dir, name, next, &inode, NAMEI_FOLLOW) == EOF)
            goto rollback;
        iput(dir);
        dir = inode;
        if (!ISDIR(dir->mode) || !dir->op->permission(dir, P_EXEC))
            goto rollback;
        if (lastname == *next)
            return dir;
        name = *next;
    }

rollback:
    iput(dir);
    return NULL;
}

// 获得 pathame 的目录的末尾文件的目录
inode_t *named(char *pathname, char **next)
{
    task_t *task = running_task();
    inode_t *dir = NULL;
    char *lhs = pathname;

    if (IS_SEPARATOR(*lhs))
    {
        dir = task->iroot;
        lhs++;
    }
    else if (*lhs)
        dir = task->ipwd;
    else
        return NULL;
    return namedd(lhs, next, dir);
}

// 获取 pathname 对应的 inode
inode_t *nameid(char *pathname, inode_t *ipwd)
{
    char *name = NULL;
    inode_t *dir = namedd(pathname, &name, ipwd);
    if (!dir)
        return NULL;

    if (!name[0])
        return dir;

    inode_t *inode = NULL;
    char *next = NULL;

    // 返回上一级目录且上一级目录是个挂载点
    if (match_name(name, "..", &next) && dir == dir->super->iroot)
    {
        super_t *super = dir->super;
        inode = super->imount;
        inode->count++;
        iput(dir);
        dir = inode;
    }

    int ret = dir->op->namei(dir, name, &next, &inode, NAMEI_FOLLOW);

    if (inode && !ISDIR(inode->mode) && next)
    {
        iput(inode);
        inode = NULL;
    }

    iput(dir);
    return inode;
}

// 获取 pathname 对应的 inode
inode_t *namei(char *pathname)
{
    char *name = NULL;
    inode_t *dir = named(pathname, &name);
    if (!dir)
        return NULL;

    if (!name[0])
        return dir;

    char *next = NULL;
    inode_t *inode = NULL;

    // 返回上一级目录且上一级目录是个挂载点
    if (match_name(name, "..", &next) && dir == dir->super->iroot)
    {
        super_t *super = dir->super;
        inode = super->imount;
        inode->count++;
        iput(dir);
        dir = inode;
    }

    int ret = dir->op->namei(dir, name, &next, &inode, NAMEI_FOLLOW);

    if (inode && !ISDIR(inode->mode) && next)
    {
        iput(inode);
        inode = NULL;
    }

    iput(dir);
    return inode;
}

// 返回符号链接自身
inode_t *lnamei(char *pathname)
{
    char *name = NULL;
    inode_t *dir = named(pathname, &name);
    if (!dir)
        return NULL;

    if (!name[0])
        return dir;

    char *next = NULL;
    inode_t *inode = NULL;

    // 返回上一级目录且上一级目录是个挂载点
    if (match_name(name, "..", &next) && dir == dir->super->iroot)
    {
        super_t *super = dir->super;
        inode = super->imount;
        inode->count++;
        iput(dir);
        dir = inode;
    }

    int ret = dir->op->namei(dir, name, &next, &inode, 0);

    if (inode && !ISDIR(inode->mode) && next)
    {
        iput(inode);
        inode = NULL;
    }

    iput(dir);
    return inode;
}